from PyQt5.QtCore import QThread
import Face_Recognition_Window
import Face_Acquisition_Window
import Login
import sys
import cv2
import sqlite3
import os
from PIL import Image
import numpy as np
from PyQt5 import QtCore, QtWidgets, QtCore,QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QFileDialog, QMessageBox
class Recognition_Window(Face_Recognition_Window.Ui_MainWindow,QMainWindow):
    def __init__(self):
        super(Recognition_Window, self).__init__()
        self.setupUi(self)
class Acquisition_Window(Face_Acquisition_Window.Ui_MainWindow,QMainWindow):
    def __init__(self):
        super(Acquisition_Window, self).__init__()
        self.setupUi(self)
class Login_Window(Login.Ui_MainWindow,QMainWindow):
    def __init__(self):
        super(Login_Window, self).__init__()
        self.setupUi(self)#插入人脸识别需要的识别器
        self.timer_camera = QtCore.QTimer()  # 定义定时器，用于控制显示视频的帧率
        self.timer_camera1=QtCore.QTimer()
        self.cap = cv2.VideoCapture()  # 视频流
        self.faceCascade = cv2.CascadeClassifier(
            './data1/lbpcascade_frontalface_improved.xml')
        self.recognizer = cv2.face.LBPHFaceRecognizer_create()
        self.recognizer.read('trainer/trainer.yml')
        self.facetrain=FaceTrain()

        self.Rec_Window = Recognition_Window()#人脸识别窗口
        self.Acq_Window=Acquisition_Window()#人脸采集窗口

        self.pushButton.clicked.connect(self.show_Acq)#打开人脸采集窗口
        self.pushButton_2.clicked.connect(self.show_Rec)#打开人脸识别窗口

        self.Acq_Window.revert.clicked.connect(self.close_Acq_Window)
        self.Acq_Window.open_camear.clicked.connect(self.button_open_camear)
        self.Acq_Window.Picture_coll.clicked.connect(self.write_Png)
        self.Acq_Window.save_info.clicked.connect(self.save_infomtion)
        self.timer_camera.timeout.connect(self.show_camear)

        self.Rec_Window.revert.clicked.connect(self.close_Rec_Window)
        self.Rec_Window.open_camear.clicked.connect(self.button_open_camear1)
        self.timer_camera1.timeout.connect(self.Faces_Recognition)


    def show_Rec(self):
        self.facetrain.start()
        self.Rec_Window.show()
        self.hide()

    def show_Acq(self):
        self.Acq_Window.show()
        self.hide()

    def close_Acq_Window(self):
        self.Acq_Window.close()
        self.timer_camera.stop()
        self.cap.release()
        self.Acq_Window.camear.clear()
        self.show()

    def close_Rec_Window(self):
        self.Rec_Window.close()
        self.timer_camera1.stop()
        self.cap.release()
        self.Rec_Window.camear.clear()
        self.show()

#人脸采集窗口调用摄像头控制
    def button_open_camear(self):
        try:
            if self.timer_camera.isActive() == False:
                flag = self.cap.open(0)
                if flag == False:
                    self.Tips("请检查相机于电脑是否连接正确")
                else:
                    self.timer_camera.start(30)
                    self.Acq_Window.open_camear.setText("关闭摄像头")

            else:
                self.timer_camera.stop()
                self.cap.release()
                self.Acq_Window.camear.clear()
                self.Acq_Window.open_camear.setText("打开摄像头")
        except:
            pass
    #人脸识别调用摄像头
    def button_open_camear1(self):
        try:
            if self.timer_camera1.isActive() == False:
                flag = self.cap.open(0)
                if flag == False:
                    self.Tips("请检查相机于电脑是否连接正确")
                else:
                    self.timer_camera1.start(30)
                    self.Rec_Window.open_camear.setText("关闭摄像头")

            else:
                self.timer_camera1.stop()
                self.cap.release()
                self.Rec_Window.camear.clear()
                self.Rec_Window.open_camear.setText("打开摄像头")
        except:
            pass

# 人脸采集过程========================================================
    def show_camear(self):
        flag,self.image=self.cap.read()
        self.images=cv2.cvtColor(self.image,cv2.COLOR_BGR2GRAY)
        self.image1=self.image
        faces=self.faceCascade.detectMultiScale(self.images)
        img_face=self.image.copy()
        for x,y,w,h in faces:
            cv2.rectangle(img_face,(x,y),(x+w,y+h),(0,255,0),thickness=2)
        show = cv2.resize(img_face, (620, 540))  # 把读到的帧的大小重新设置为 640x480
        show = cv2.flip(show, 1)
        show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)  # 视频色彩转换回RGB，这样才是现实的颜色
        showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0],
                                 QtGui.QImage.Format_RGB888)  # 把读取到的视频数据变成QImage形式
        self.Acq_Window.camear.setPixmap(QtGui.QPixmap.fromImage(showImage))  # 往显示视频的Label里 显示QImage
    #图片保存
    def write_Png(self):
        try:
            self.Acq_Window.name1.clear()
            self.Acq_Window.Sno1.clear()
            self.Acq_Window.Sdt1.clear()
            self.Acq_Window.major1.clear()
            self.Acq_Window.clas1.clear()
            self.Acq_Window.picture.clear()
            self.image1 = cv2.flip(self.image1, 1)
            cv2.imwrite('./image/' + "aaaa" + '.jpg', self.image1)
            self.Acq_Window.picture.setPixmap(QtGui.QPixmap("./image/aaaa.jpg"))
            self.Acq_Window.picture.setScaledContents(True)
        except:
            pass

    #人脸采集
    def save_infomtion(self):
        try:
            Sno = self.Acq_Window.Sno1.text()
            name = self.Acq_Window.name1.text()  # 名字
            Sdt = self.Acq_Window.Sdt1.text()  # 学部
            major = self.Acq_Window.major1.text()  # 专业
            class1 = self.Acq_Window.clas1.text()  # 班级
            info = [Sno, name, Sdt, major, class1]
            if (Sno and name and Sdt and major and class1):
                os.rename("./image/aaaa.jpg","./person/"+Sno+".jpg")
                conn = sqlite3.connect('student.db')
                sour = conn.cursor()
                sour.execute("insert into Student (Sno,name,Sdt,major,class) values (?,?,?,?,?)", info)
                sour.close()
                conn.commit()
                conn.close()
                self.Acq_Window.name1.clear()
                self.Acq_Window.Sno1.clear()
                self.Acq_Window.Sdt1.clear()
                self.Acq_Window.major1.clear()
                self.Acq_Window.clas1.clear()
                self.Acq_Window.picture.clear()
                self.Tips("信息录入成功")
            else:
                self.Tips("请填写完整信息！")
        except:
            self.Tips("学生信息录入失败！")

#人脸数据训练
    def face_train(self):
        try:
            facesSamples = []
            ids = []
            path = 'person/'
            imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
            # 检测人脸
            face_detector = cv2.CascadeClassifier(
                './data1/lbpcascade_frontalface_improved.xml')
            # 遍历列表中的图片
            for imagePath in imagePaths:
                # 打开图片,黑白化
                PIL_img = Image.open(imagePath).convert('L')
                # 将图像转换为数组，以黑白深浅
                # PIL_img = cv2.resize(PIL_img, dsize=(400, 400))
                img_numpy = np.array(PIL_img, 'uint8')
                # 获取图片人脸特征
                faces = face_detector.detectMultiScale(img_numpy)
                # 获取每张图片的id和姓名
                id = int(imagePath.split('/')[-1].split('.')[0])
                # 预防无面容照片
                for x, y, w, h in faces:
                    ids.append(id)
                    facesSamples.append(img_numpy[y:y + h, x:x + w])
            recognizer = cv2.face.LBPHFaceRecognizer_create()
            # recognizer.train(faces,names)#np.array(ids)
            recognizer.train(facesSamples, np.array(ids))
            # 保存文件
            recognizer.write('./trainer/trainer.yml')
        except:
            pass
#人脸识别============================================================

            # 人脸识别
    def Faces_Recognition(self):
        try:
            flag, self.frame = self.cap.read()
            self.frame=cv2.flip(self.frame,1)
            gray = cv2.cvtColor(self.frame, cv2.COLOR_BGR2GRAY)  # 转换为灰度

            # 加载分类器
            face_detector = cv2.CascadeClassifier(
                './data1/lbpcascade_frontalface_improved.xml')
            face = face_detector.detectMultiScale(gray, 1.1, 5, cv2.CASCADE_SCALE_IMAGE, (100, 100), (300, 300))
            for x, y, w, h in face:
                # 人脸识别
                id, confidence = self.recognizer.predict(gray[y:y + h, x:x + w])
                # print(id)
                if confidence > 70:
                    cv2.rectangle(self.frame, (x, y), (x + w, y + h), color=(0, 0, 255), thickness=2)
                    cv2.putText(self.frame, 'unkonw', (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0),
                                1)
                    self.Rec_Window.Sno1.clear() # 学号
                    self.Rec_Window.name1.clear()  # 名字
                    self.Rec_Window.Sdt1.clear() # 学部
                    self.Rec_Window.major1.clear()# 专业
                    self.Rec_Window.clas1.clear()# 班级
                    # cv2.rectangle(person, (x, y), (x + w, y + h), color=(0, 0, 255), thickness=2)
                else:
                    cv2.rectangle(self.frame, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2)
                    ids = self.select(id=id)
                    if ids:
                        self.Rec_Window.Sno1.setText(ids[0])  # 学号
                        self.Rec_Window.name1.setText(ids[1])  # 名字
                        self.Rec_Window.Sdt1.setText(ids[2])  # 学部
                        self.Rec_Window.major1.setText(ids[3])  # 专业
                        self.Rec_Window.clas1.setText(ids[4])  # 班级
            show = cv2.resize(self.frame, (620, 540))  # 把读到的帧的大小重新设置为 640x480
            show = cv2.cvtColor(show, cv2.COLOR_BGR2RGB)  # 视频色彩转换回RGB，这样才是现实的颜色
            showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0],
                                        QtGui.QImage.Format_RGB888)  # 把读取到的视频数据变成QImage形式
            self.Rec_Window.camear.setPixmap(QtGui.QPixmap.fromImage(showImage))  # 往显示视频的Label里 显示QImage
        except:
            pass




    def select(self,id):
        try:
            conn = sqlite3.connect("student.db")
            sour = conn.cursor()
            sour.execute("select * from Student where Sno=?", (id,))
            ids = sour.fetchall()[0]
            sour.close()
            conn.close()
            return ids
        except:
            pass



    def Tips(self, message):
        QMessageBox.about(self, "提示", message)


#人脸模型训练
class FaceTrain(QThread):
    def __init__(self):
        super(FaceTrain, self).__init__()
    def run(self):
        try:
            facesSamples = []
            ids = []
            path = './person/'
            imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
            if(len(imagePaths)==0):
                QMessageBox.about(self, "提示", "未检出人脸信息，请先采集人脸")
            # 检测人脸
            face_detector = cv2.CascadeClassifier(
                './data1/lbpcascade_frontalface_improved.xml')
            # 遍历列表中的图片
            for imagePath in imagePaths:
                # 打开图片,黑白化
                PIL_img = Image.open(imagePath).convert('L')
                # 将图像转换为数组，以黑白深浅
                # PIL_img = cv2.resize(PIL_img, dsize=(400, 400))
                img_numpy = np.array(PIL_img, 'uint8')
                # 获取图片人脸特征
                faces = face_detector.detectMultiScale(img_numpy)
                # 获取每张图片的id和姓名
                id = int(imagePath.split('/')[-1].split('.')[0])
                # 预防无面容照片
                for x, y, w, h in faces:
                    ids.append(id)
                    facesSamples.append(img_numpy[y:y + h, x:x + w])

            recognizer = cv2.face.LBPHFaceRecognizer_create()
            # recognizer.train(faces,names)#np.array(ids)
            recognizer.train(facesSamples, np.array(ids))
            # 保存文件
            recognizer.write('./trainer/trainer.yml')
        except:
            pass





if __name__ == '__main__':
    # 这里是界面的入口，在这里需要定义QApplication对象，之后界面跳转时不用再重新定义，只需要调用show()函数即可
    app = QApplication(sys.argv)
    # 显示创建的界面
    Log_window = Login_Window()
    Log_window.show()
    sys.exit(app.exec_())

